﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;

namespace Extractor.DAL
{
    /// <summary>
    /// Provide access for all application data
    /// </summary>
    public class DataAccess
    {
        #region Data Members

        private readonly static object SyncObject = new object();

        private const string DATASET_FILE_NAME = "MediaControllerDataSet.xml";

        private static DataAccess _instance;

        private MediaControllerDataSet _mediaControllerDataSet;

        private readonly string _applicationFolder;

        Timer _saveTimer = new Timer();

        #endregion


        /// <summary>
        /// Application data set
        /// </summary>
        public MediaControllerDataSet MediaControllerDataSet
        {
            get { return _mediaControllerDataSet; }
        }

        /// <summary>
        /// Access to singeltone object
        /// </summary>
        public static DataAccess Instance
        {
            get
            {
                lock (SyncObject)
                {
                    if (_instance == null)
                    {
                        _instance = new DataAccess();
                    }
                }
                return _instance;
            }
        }

        protected DataAccess()
        {
            //_isoStore = IsolatedStorageFile.GetStore(IsolatedStorageScope.User | IsolatedStorageScope.Assembly, null, null);
            _applicationFolder = Application.UserAppDataPath;// Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
            _mediaControllerDataSet = new MediaControllerDataSet();

            LoadData();
            _saveTimer.Interval = Convert.ToInt32(TimeSpan.FromMinutes(1).TotalMilliseconds);
            _saveTimer.Tick += SaveTimerTick;
            _saveTimer.Start();
        }



        /// <summary>
        /// Save data
        /// </summary>
        public void SaveData()
        {
            _mediaControllerDataSet.AcceptChanges();
            //var oStream = new IsolatedStorageFileStream(DATASET_FILE_NAME, FileMode.Create, _isoStore);
            string dataSetPath = Path.Combine(_applicationFolder, DATASET_FILE_NAME);

            using (var writer = new StreamWriter(dataSetPath))
            {
                _mediaControllerDataSet.WriteXml(writer);
                writer.Close();
            }
        }

        /// <summary>
        /// Load saved data
        /// </summary>
        public void LoadData()
        {
            InitDataSet();

            string dataSetPath = Path.Combine(_applicationFolder, DATASET_FILE_NAME);

            using (var reader = new StreamReader(dataSetPath))
            {
                try
                {
                    _mediaControllerDataSet.ReadXml(reader);
                }
                catch (Exception)
                {
                    InitDataSet();
                }
                reader.Close();
            }
        }

        /// <summary>
        /// Reset all data
        /// </summary>
        public void Reset()
        {
            string dataSetPath = Path.Combine(_applicationFolder, DATASET_FILE_NAME);
            File.Delete(dataSetPath);
            //_isoStore.DeleteFile(DATASET_FILE_NAME);
            InitDataSet();
        }

        public MediaControllerDataSet.RegexRow[] GetPrioritizeRegex(eRegexType regexType)
        {
            string filter;
            switch (regexType)
            {
                case eRegexType.Determine:
                    filter = string.Format("RegexTypeId = {0}", (int)eRegexType.Determine);
                    break;
                case eRegexType.Cleaner:
                    filter = string.Format("RegexTypeId = {0}", (int)eRegexType.Cleaner);
                    break;
                case eRegexType.SearchPattern:
                    filter = string.Format("RegexTypeId = {0}", (int)eRegexType.SearchPattern);
                    break;
                default:
                    throw new ArgumentOutOfRangeException("regexType");
            }
            var regexRows = (MediaControllerDataSet.RegexRow[])_mediaControllerDataSet.Regex.Select(filter);

            var pruiritizeDic = new SortedDictionary<int, MediaControllerDataSet.RegexRow>();
            foreach (var regexRow in regexRows)
            {
                pruiritizeDic.Add(regexRow.Priority, regexRow);
            }
            return new List<MediaControllerDataSet.RegexRow>(pruiritizeDic.Values).ToArray();
        }

        public MediaControllerDataSet.RegexRow[] GetPrioritizeRegex(eRegexType regexType, int categoryId)
        {
            string filter;
            switch (regexType)
            {
                case eRegexType.Determine:
                    filter = string.Format("RegexTypeId = {0} AND CategoryId = {1}", (int)eRegexType.Determine, categoryId);
                    break;
                case eRegexType.Cleaner:
                    filter = string.Format("RegexTypeId = {0} AND CategoryId = {1}", (int)eRegexType.Cleaner, categoryId);
                    break;
                case eRegexType.SearchPattern:
                    filter = string.Format("RegexTypeId = {0} AND CategoryId = {1}", (int)eRegexType.SearchPattern, categoryId);
                    break;
                default:
                    throw new ArgumentOutOfRangeException("regexType");
            }
            var regexRows = (MediaControllerDataSet.RegexRow[])_mediaControllerDataSet.Regex.Select(filter);

            var pruiritizeDic = new SortedDictionary<int, MediaControllerDataSet.RegexRow>();
            foreach (var regexRow in regexRows)
            {
                pruiritizeDic.Add(regexRow.Priority, regexRow);
            }
            return new List<MediaControllerDataSet.RegexRow>(pruiritizeDic.Values).ToArray();
        }

        #region Private Methods

        /// <summary>
        /// Save data evry 1 min
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void SaveTimerTick(object sender, EventArgs e)
        {
            SaveData();
        }

        private void InitDataSet()
        {
            string dataSetPath = Path.Combine(_applicationFolder, DATASET_FILE_NAME);

            if (!File.Exists(dataSetPath))
            {
                _mediaControllerDataSet = new MediaControllerDataSet();
                InitStatuses();
                InitCategories();
                InitRegexTypes();
                InitRegex();

                InitDestinations();

                _mediaControllerDataSet.AcceptChanges();
                SaveData();
            }

        }

        private void InitDestinations()
        {
            var destinationsRow = _mediaControllerDataSet.Destinations.NewDestinationsRow();
            destinationsRow.CategoryId = -1;
            destinationsRow.Destination = string.Format("{0}\\{1}", Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Series\\<MediaName>\\<Directory>\\<FileName>");
            _mediaControllerDataSet.Destinations.AddDestinationsRow(destinationsRow);

            destinationsRow = _mediaControllerDataSet.Destinations.NewDestinationsRow();
            destinationsRow.CategoryId = -2;
            destinationsRow.Destination = string.Format("{0}\\{1}", Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Movies\\<Directory>\\<FileName>");
            _mediaControllerDataSet.Destinations.AddDestinationsRow(destinationsRow);
        }

        private void InitRegexTypes()
        {
            var regexTypeRow = _mediaControllerDataSet.RegexType.NewRegexTypeRow();
            regexTypeRow.Name = "Determine";
            _mediaControllerDataSet.RegexType.AddRegexTypeRow(regexTypeRow);

            regexTypeRow = _mediaControllerDataSet.RegexType.NewRegexTypeRow();
            regexTypeRow.Name = "Cleaner";
            _mediaControllerDataSet.RegexType.AddRegexTypeRow(regexTypeRow);

            regexTypeRow = _mediaControllerDataSet.RegexType.NewRegexTypeRow();
            regexTypeRow.Name = "Search Pattern";
            _mediaControllerDataSet.RegexType.AddRegexTypeRow(regexTypeRow);
        }

        private void InitCategories()
        {
            var categoriesRow = _mediaControllerDataSet.Categories.NewCategoriesRow();
            categoriesRow.Name = "Series";
            _mediaControllerDataSet.Categories.AddCategoriesRow(categoriesRow);

            categoriesRow = _mediaControllerDataSet.Categories.NewCategoriesRow();
            categoriesRow.Name = "Movies";
            _mediaControllerDataSet.Categories.AddCategoriesRow(categoriesRow);

            _mediaControllerDataSet.Categories.AcceptChanges();
        }

        private void InitRegex()
        {
            #region Series
            var regexRow = _mediaControllerDataSet.Regex.NewRegexRow();
            regexRow.Name = "Series Detrmine";
            regexRow.CategoryId = (int)eCategory.Series;
            regexRow.RegexTypeId = (int)eRegexType.Determine;
            regexRow.RegexTypeId = -1;
            regexRow.Priority = 1;
            regexRow.Regex = @".*(?i)s\d{1,2}e\d{1,2}.*|.*(?i)s\d{1,2}.e\d{1,2}.*|\d{1,2}x\d{1,2}";
            regexRow.Enabled = true;
            _mediaControllerDataSet.Regex.AddRegexRow(regexRow);

            regexRow = _mediaControllerDataSet.Regex.NewRegexRow();
            regexRow.Name = "Series Cleaner";
            regexRow.CategoryId = (int)eCategory.Series;
            regexRow.RegexTypeId = (int)eRegexType.Cleaner;
            regexRow.Priority = 1;
            regexRow.Regex = @"576p|720p|1080p|1080i|dircut|directors cut|dvdrip|dvdscreener|dvdscr|avchd|wmv|ntsc|pal|mpeg|dsr|hd|r5|dvd|dvdr|dvd5|dvd9|bd5|bd9|dts|ac3|bluray|blu-ray|hdtv|pdtv|stv|hddvd|xvid|divx|x264|dxva|(?-i)FESTIVAL|LIMITED|WS|FS|PROPER|REPACK|RERIP|REAL|RETAIL|EXTENDED|REMASTERED|UNRATED|CHRONO|THEATRICAL|DC|SE|UNCUT|INTERNAL|DUBBED|SUBBED";
            regexRow.Enabled = true;
            _mediaControllerDataSet.Regex.AddRegexRow(regexRow);

            regexRow = _mediaControllerDataSet.Regex.NewRegexRow();
            regexRow.Name = "Series";
            regexRow.Regex = @"(?i-:(?<MediaName>.*?)(\.){0,1}S(\d){1,2}(\.){0,1}E(\d){1,2})";
            regexRow.CategoryId = (int)eCategory.Series;
            regexRow.RegexTypeId = (int)eRegexType.SearchPattern;
            regexRow.Priority = 1;
            regexRow.Enabled = true;
            _mediaControllerDataSet.Regex.AddRegexRow(regexRow);

            #endregion

            #region Movies

            regexRow = _mediaControllerDataSet.Regex.NewRegexRow();
            regexRow.Name = "Movies Detrmine";
            regexRow.CategoryId = (int)eCategory.Movie;
            regexRow.RegexTypeId = (int)eRegexType.Determine;
            regexRow.RegexTypeId = -1;
            regexRow.Priority = 3;
            regexRow.Regex = @".*";
            regexRow.Enabled = true;
            _mediaControllerDataSet.Regex.AddRegexRow(regexRow);

            regexRow = _mediaControllerDataSet.Regex.NewRegexRow();
            regexRow.Name = "Movies Cleaner";
            regexRow.CategoryId = (int)eCategory.Movie;
            regexRow.RegexTypeId = (int)eRegexType.Cleaner;
            regexRow.Priority = 2;
            regexRow.Regex = @"576p|720p|1080p|1080i|dircut|directors cut|dvdrip|dvdscreener|dvdscr|avchd|wmv|ntsc|pal|mpeg|dsr|hd|r5|dvd|dvdr|dvd5|dvd9|bd5|bd9|dts|ac3|bluray|blu-ray|hdtv|pdtv|stv|hddvd|xvid|divx|x264|dxva|(?-i)FESTIVAL|LIMITED|WS|FS|PROPER|REPACK|RERIP|REAL|RETAIL|EXTENDED|REMASTERED|UNRATED|CHRONO|THEATRICAL|DC|SE|UNCUT|INTERNAL|DUBBED|SUBBED";
            regexRow.Enabled = true;
            _mediaControllerDataSet.Regex.AddRegexRow(regexRow);

            regexRow = _mediaControllerDataSet.Regex.NewRegexRow();
            regexRow.Name = "Movies SearchPattern";
            regexRow.CategoryId = (int)eCategory.Movie;
            regexRow.RegexTypeId = (int)eRegexType.SearchPattern;
            regexRow.Priority = 1;
            regexRow.Regex = @"^(?i-:(?<MediaName>.*?)\.(576p|720p|1080p|1080i|dircut|directors cut|dvdrip|dvdscreener|dvdscr|avchd|wmv|ntsc|pal|mpeg|dsr|hd|r5|dvd|dvdr|dvd5|dvd9|bd5|bd9|dts|ac3|bluray|blu-ray|hdtv|pdtv|stv|hddvd|xvid|divx|x264|dxva|(?-i)FESTIVAL|LIMITED|WS|FS|PROPER|REPACK|RERIP|REAL|RETAIL|EXTENDED|REMASTERED|UNRATED|CHRONO|THEATRICAL|DC|SE|UNCUT|INTERNAL|DUBBED|SUBBED|\d\d\d))";
            regexRow.Enabled = true;
            _mediaControllerDataSet.Regex.AddRegexRow(regexRow);

            #endregion

            _mediaControllerDataSet.Regex.AcceptChanges();
        }

        private void InitStatuses()
        {
            var statusesRow = _mediaControllerDataSet.Statuses.NewStatusesRow();
            statusesRow.Name = "All";
            _mediaControllerDataSet.Statuses.AddStatusesRow(statusesRow);

            statusesRow = _mediaControllerDataSet.Statuses.NewStatusesRow();
            statusesRow.Name = "New";
            _mediaControllerDataSet.Statuses.AddStatusesRow(statusesRow);

            statusesRow = _mediaControllerDataSet.Statuses.NewStatusesRow();
            statusesRow.Name = "Active";
            _mediaControllerDataSet.Statuses.AddStatusesRow(statusesRow);

            statusesRow = _mediaControllerDataSet.Statuses.NewStatusesRow();
            statusesRow.Name = "Done";
            _mediaControllerDataSet.Statuses.AddStatusesRow(statusesRow);

            statusesRow = _mediaControllerDataSet.Statuses.NewStatusesRow();
            statusesRow.Name = "Deleted";
            _mediaControllerDataSet.Statuses.AddStatusesRow(statusesRow);
        }

        #endregion
    }


    internal enum eCategory
    {
        Series = -1,
        Movie = -2
    }

    public enum eRegexType
    {
        Determine = -1,
        Cleaner = -2,
        SearchPattern = -3
    }

    public enum eFileStatus
    {
        All = -1,
        New = -2,
        Active = -3,
        Done = -4,
        Deleted = -5

    }
}
